package im.composer.media.sound.codec;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.sound.sampled.spi.AudioFileReader;

import org.kc7bfi.jflac.FLACDecoder;
import org.kc7bfi.jflac.frame.Frame;
import org.kc7bfi.jflac.metadata.StreamInfo;
import org.kc7bfi.jflac.util.ByteData;
import org.tritonus.share.sampled.AudioFileTypes;

import im.composer.media.audio.stream.LinkedByteArrayInputStream;

public class FLACFileReader extends AudioFileReader {

	@Override
	public AudioFileFormat getAudioFileFormat(InputStream stream) throws UnsupportedAudioFileException, IOException {
		FLACDecoder decoder = new FLACDecoder(stream);
		StreamInfo stream_info = decoder.readStreamInfo();
		return new AudioFileFormat(new AudioFileTypes("FLAC", "flac"), stream_info.getAudioFormat(), (int) stream_info.getTotalSamples());
	}

	@Override
	public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException {
		return getAudioFileFormat(url.openStream());
	}

	@Override
	public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException {
		return getAudioFileFormat(new FileInputStream(file));
	}

	@Override
	public AudioInputStream getAudioInputStream(InputStream stream) throws UnsupportedAudioFileException, IOException {
		FLACDecoder decoder = new FLACDecoder(stream);
		StreamInfo si = decoder.readStreamInfo();
		AudioFormat format = si.getAudioFormat();
		InputStream lbais = new LinkedByteArrayInputStream() {
			ByteData bd = null;

			@Override
			public int available() throws IOException {
				if (super.available() == 0) {
					if (decoder.isEOF()) {
						close();
					} else {
						Frame frame = decoder.readNextFrame();
						bd = decoder.decodeFrame(frame, bd);
						byte[] b_arr = Arrays.copyOf(bd.getData(), bd.getLen());
						offer(b_arr);
					}
				}
				return super.available();
			}

		};
		return new AudioInputStream(lbais, format, si.getTotalSamples());
	}

	@Override
	public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException {
		return getAudioInputStream(url.openStream());
	}

	@Override
	public AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException {
		return getAudioInputStream(new FileInputStream(file));
	}

}
